package com.stars.easyms.demo.rest.service.jdk8;

import com.stars.easyms.rest.RestService;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.*;

/**
 * <p>className: EasyMsJdk8Demo9Service</p>
 * <p>description: Stream API</p>
 *
 * @author guoguifang
 * @date 2019/9/23 16:53
 * @since 1.3.2
 */
@Service
public class EasyMsJdk8Demo9Service implements RestService<Void, Void> {

    @Override
    public Void execute(Void input) {

        // 1.通过Stream的builder构建
        Stream<String> stream = Stream.<String>builder().add("a").add("b").add("c").build();

        // 2.通过Stream.of方法构建，这种方法可以用来处理数组
        String[] array = new String[]{"a", "b", "c"};
        stream = Stream.of(array);
        stream = Stream.of("a", "b", "c");

        // 3.通过Collection类的stream方法构建，这是最常用的方法
        Collection<String> list = Arrays.asList("a", "b", "c");
        stream = list.stream();

        // 4.通过IntStream、LongStream、DoubleStream构建
        IntStream intStream = IntStream.of(1, 2, 3);
        LongStream longStream = LongStream.range(0L, 10L);
        DoubleStream doubleStream = DoubleStream.of(1.1d, 1.2d, 2.1d);

        // 5.通过StreamSupport来构建
        stream = StreamSupport.stream(list.spliterator(), false);

        // limit 方法用于获取指定数量的流。sorted 方法用于对流进行排序。使用 forEach 输出了10个随机数：
        // Collectors 类实现了很多归约操作，例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串：
        String mergedString = new Random().ints(100, 1000).limit(10).sorted()
                .mapToObj(String::valueOf).collect(Collectors.joining(", "));
        System.out.println("合并字符串: " + mergedString);

        // distinct操作，很显然这是一个去重操作，会根据每个元素的equals方法去重。
        List<Integer> squaresList = Stream.of("1", "2,3", "4,3,2")
                .flatMap(s -> Stream.of(s.split(",")))
                .mapToInt(Integer::parseInt)
                .mapToObj(i -> i * i)
                .distinct().collect(Collectors.toList());
        System.out.println(squaresList);

        // 将返回一个只包含大于1的元素的数组
        Integer[] integerArray = Stream.of(1, 2, 3).filter(i -> i > 1).toArray(Integer[]::new);
        System.out.println("大于1的元素数组为：" + Arrays.asList(integerArray));

        // 获取空字符串的数量，parallelStream 是流并行处理程序的代替方法
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
        long count = strings.parallelStream().filter(String::isEmpty).count();
        System.out.println("空字符串数量为: " + count);

        count = strings.stream().filter(string -> string.length() == 3).count();
        System.out.println("字符串长度为 3 的数量为: " + count);

        // peek操作，参数为Consumer，改操作会处理每个元素，但不会返回新的对象。
        Stream.of(new User("xiaoming", 10),
                new User("xiaoli", 15),
                new User("xiaolin", 21),
                new User("xiaoxiao", 40))
                .peek(user -> {
                    user.name += " eat a mantou";
                    user.age += 2;
                })
                .skip(2)
                .forEach(user -> System.out.println("name:" + user.name + ", age:" + user.age));

        // allMatch、anyMatch、noneMatch操作，都就接收一个Predicate，用于匹配查询
        boolean b1 = Stream.of("hello", "hi", "haha", "hehe").allMatch("hello"::equals);
        boolean b2 = Stream.of("hello", "hi", "haha", "hehe").anyMatch("hello"::equals);
        boolean b3 = Stream.of("hello", "hi", "haha", "hehe").noneMatch("hello"::equals);
        System.out.println(b1 + "," + b2 + "," + b3);

        // findFirst、findAny操作，都会返回流中的一个元素，返回值使用Optional包装。
        String first = Stream.of("hello", "hi", "haha", "hehe").findFirst().get();
        String any = Stream.of("hello", "hi", "haha", "hehe").filter("a"::equals).findAny().orElse("not found");
        System.out.println(first + ", " + any);

        // max、min、count操作，这三个操作都比较简单，分别返回流中最大值、最小值和元素个数
        String max = Stream.of("hello", "hi", "haha", "hehe").max(Comparator.comparingInt(String::length)).get();
        String min = Stream.of("hello", "hi", "haha", "hehe").min(Comparator.comparingInt(String::length)).get();
        long c = Stream.of("hello", "hi", "haha", "hehe").count();
        System.out.println("max:" + max + ",min:" + min + ",count:" + c);

        // 统计功能
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
        System.out.println("列表中最大的数:" + stats.getMax() + ", 列表中最小的数:" + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum() + ", 平均数 : " + stats.getAverage());

        // 单次统计功能
        Stream.of("abc", "bcd,abc", "edf", "", "edf,bcd,", "abc,abc,abc")
                .flatMap(s -> Stream.of(s.split(",")))
                .filter(s -> !s.isEmpty())
                .sorted()
                .collect(Collectors.toMap(key -> key, value -> 1,
                        (oldValue, newValue) -> oldValue + newValue,
                        LinkedHashMap::new))
                .forEach((k, v) -> System.out.println(k + ":" + v));

        // 分组
        Map<String, List<User>> map = Stream.of(
                new User("xiaoming", 10),
                new User("xiaoli", 15),
                new User("xiaoli", 21),
                new User("xiaoming", 40))
                .collect(Collectors.groupingBy(User::getName));
        map.forEach((key, value) -> System.out.println(key + "," + value));

        long[] arrayOfLong = new long[20];
        // 并发设置数组所有值
        Arrays.parallelSetAll(arrayOfLong, index -> ThreadLocalRandom.current().nextInt(1000));
        // 并发排序
        Arrays.parallelSort(arrayOfLong);
        Arrays.stream(arrayOfLong).limit(10).forEach(i -> System.out.print(i + " "));

        return null;
    }

}

@Data
@AllArgsConstructor
class User {

    public String name;

    public int age;
}